--------------------------------------------------------------------------------------------------------------------------------------- 
--版权声明：本demo集源于上海合宙官方技术团队的DEMO（MIT），并参考了合宙开源社区的众多大佬无私分享的代码，包括但不限于 稀饭放姜、Wendal、晨旭、陈夏等
-- 目前参考到的开源项目有： iRTU（MIT)、LuatOS(MIT)、LLCOM(Apache2)
-- 欲获取更多luat 代码请访问 doc.openluat.com
-- 如果您觉得本demo集包含了未经由您授权的代码，请联系 64034373@qq.com 
---------------------------------------------------------------------------------------------------------------------------------------

-- @模块功能：GPIO双向控制
-- @author miuser
-- @module midemo.bio
-- @license MIT
-- @copyright miuser@luat
-- @release 2020-08-29
--------------------------------------------------------------------------
-- @使用方法
-- @串口收到形如SETGPIO,pio,level的指令后，对应的pio引脚设置为level状态，比如 串口收到SETGPIO,13,1，则GPIO13引脚被设置为弱高电平
-- @当任意双向引脚的电平发生变化时，本模块发送 GPIO_LEVEL_CHANGE 主题的消息，比如上条指令将发送系统消息 GPIO_LEVEL_CHANGE,13,1
-- @发生电平变化的原因可以是内部指令造成的或者外部电路造成的，GPIO_LEVEL_CHANGE仅反映引脚的真实电平状态变化，当发生状态冲突，以实际外部电平为准
-- @当串口收到SETGPIO指令时，串口将收到中文提示 GPIOxx当前电平为高/低的提示，如果电平发生真实的变化，串口还会收到GPIOXX上升沿/下降沿触发的提示
-- @串口收到形如GETGPIO,pio的指令后，系统发送主题为GPIO_LEVEL 主题的消息，比如串口收到 GETGPIO,13 将发送系统消息GPIO_LEVEL,13,1 
-- @同时串口将收到中文提示 GPIOxx当前电平为高/低的
-- @消息收发均采用utf8编码，与lua文件系统相同

require"pins"
require"utils"
require"pm"
require"common"

module(...,package.seeall)


--上一次的电平状态表，以管脚号为索引
 local pinLastStage={}
--获取GPIO状态的函数表，以管脚号为索引
local getGpioFnc={}
--当收到GPIO输入测试的时候执行回调函数

--通过消息发送调试信息到串口模块
function write(s)
    --log.info("testUartTask.write",s)
    sys.publish("COM",s)
    sys.publish("NET_CMD_MONI",s)
end
function gpioIntFnc(msg)
    local trigerPin=""
    local response=""
    --检测哪个IO口发生电平变化
    for i, v in ipairs(bs.BIOPins) do
        if getGpioFnc[v]()~=pinLastStage[v] then
            trigerPin=v
            pinLastStage[v]=getGpioFnc[v]()
        end
    end
    if (trigerPin=="") then return end
    local level=getGpioFnc[trigerPin]()
    --if (level==0) then write("GPIO"..tostring(trigerPin).."当前电平为低".."\r\n") else write("GPIO"..tostring(trigerPin).."当前电平为高".."\r\n") end
    if msg==cpu.INT_GPIO_POSEDGE then
        response="GPIOEDGE,"..tostring(trigerPin)..",1".."\r\n"
        write(response)
        --write("GPIO"..tostring(trigerPin).." rising".."\r\n")
        sys.publish("GPIO_LEVEL_CHANGE",trigerPin,1)
    --下降沿中断
    else
        response="GPIOEDGE,"..tostring(trigerPin)..",0".."\r\n"
        write(response)
        --write("GPIO"..tostring(trigerPin).." falling".."\r\n")
        sys.publish("GPIO_LEVEL_CHANGE",trigerPin,0)
    end
end

write("Initialing BIO")

pmd.ldoset(2,pmd.LDO_VMMC)
for i=1,#bs.BIOPins do
    pinLastStage[bs.BIOPins[i]]=0
end
for i=1,#bs.BIOPins do
    --设置中断函数和电平检测函数
    getGpioFnc[bs.BIOPins[i]]=pins.setup(bs.BIOPins[i],gpioIntFnc)
    --引脚均设为下拉
    pio.pin.setpull(pio.PULLDOWN,bs.BIOPins[i])
    write(bs.BIOPins[i].." ")
end
write("\r\n")

sys.subscribe("SETGPIO",function(...)

     io=tonumber(arg[1])
     level=tonumber(arg[2])
    if (level~=0) then 
        pio.pin.setpull(pio.PULLUP,io)                 
     else
        pio.pin.setpull(pio.PULLDOWN,io)
    end
    level=getGpioFnc[io]()
    if (level==0) then write("GPIOLEVEL,"..tostring(io)..",0".."\r\n") else write("GPIOLEVEL,"..tostring(io)..",1".."\r\n") end 
    sys.publish("GPIO_LEVEL",io,level)   
end)

sys.subscribe("GETGPIO",function(...)

    io=tonumber(arg[1])
    level=getGpioFnc[io]()
    if (level==0) then write("GPIOLEVEL,"..tostring(io)..",0".."\r\n") else write("GPIOLEVEL,"..tostring(io)..",1".."\r\n") end 
    sys.publish("GPIO_LEVEL",io,level)
end)


